/*
declare type ParameterDecorator = (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) => void;
参数列表：
target ：对于静态成员来说是类的构造函数，对于实例成员是类的原型对象
propertyKey ：成员的名字（方法名）
parameterIndex ：参数在函数参数列表中的索引
*/

//----1、收集参数装饰器标注的参数---------------------------------------------------------------------------
const registered = [];
function URLParam(id: string):ParameterDecorator {
    return (target: Object,
        propertyKey: string | symbol,
        parameterIndex: number) => {

        const topush = {
            target, propertyKey, parameterIndex, urlparam: id,
            ownKeys: Object.getOwnPropertyNames(target),
            function: target[propertyKey],
            value :target[propertyKey],
        };
        registered.push(topush);
    }
}

class BlogRouter {
    viewPost(@URLParam('id') id: string) {
        console.log(`viewPost`);
    }

    viewComments(@URLParam('commentID') commentID: string ) {
        console.log(`viewComments`);
    }
}
//const blog = new BlogRouter();
//blog.viewComments('123');
//console.log(registered);
//--------------------------------------------------------------------------------------------------------------------------------------



//----2、参数装饰器内 修改成员函数的实现，不生效---------------------------------------------------------------------------
function validateParameter(target: any, methodName: string, parameterIndex: number) {
    const originalMethod = target[methodName];

    target[methodName] = function (...args: any[]) {
        const paramValue = args[parameterIndex];
        console.log("参数值："+paramValue)
        if (typeof paramValue !== 'number' || isNaN(paramValue)) {
            throw new Error(`Invalid parameter at index ${parameterIndex}`);
        }

        console.log("参数值："+paramValue)
        return originalMethod.apply(this, args);
    };
    
}

class Example {
    someMethod(@validateParameter value: string) {
        console.log("some method.....")
    }
}

const example = new Example();
 // example.someMethod("e")
 //-------------------------------------------------------------------------------------------------------------------



 //----4、配合方法装饰器、参数装饰器 实现参数校验---------------------------------------------------------------------------
 function notNull(target: any, propertyKey: string, parameterIndex: number) {
    console.log("param decorator notNull function invoked ");
    Validator.registerNotNull(target, propertyKey, parameterIndex);
}

function validate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("method decorator validate function invoked ");
    let originalMethod = descriptor.value;
    //wrapping the original method
    descriptor.value = function (...args: any[]) {//wrapper function
        if (!Validator.performValidation(target, propertyKey, args)) {
            console.log("validation failed, method call aborted: " + propertyKey);
            return;
        }
        let result = originalMethod.apply(this, args);
        return result;
    }
}

class Validator {
    public static notNullValidatorMap: Map<any, Map<string, number[]>> = new Map();

    //todo add more validator maps
    static registerNotNull(target: any, methodName: string, paramIndex: number): void {
        let paramMap: Map<string, number[]> = this.notNullValidatorMap.get(target);
        if (!paramMap) {
            paramMap = new Map();
            this.notNullValidatorMap.set(target, paramMap);
        }
        let paramIndexes: number[] = paramMap.get(methodName);
        if (!paramIndexes) {
            paramIndexes = [];
            paramMap.set(methodName, paramIndexes);
        }
        paramIndexes.push(paramIndex);
    }

    static performValidation(target: any, methodName: string, paramValues: any[]): boolean {
        let notNullMethodMap: Map<string, number[]> = this.notNullValidatorMap.get(target);
        if (!notNullMethodMap) {
            return true;
        }
        let paramIndexes: number[] = notNullMethodMap.get(methodName);
        if (!paramIndexes) {
            return true;
        }
        let hasErrors: boolean = false;
        for (const [index, paramValue] of paramValues.entries()) {
            if (paramIndexes.indexOf(index) != -1) {
                if (!paramValue) {
                    console.error("method param at index " + index + " cannot be null");
                    hasErrors = true;
                }
            }
        }
        return !hasErrors;
    }
}

class Task {
    @validate
    run(@notNull name: string): void {
        console.log("running task, name: " + name);
    }
}

//console.log("-- creating instance --");
let task: Task = new Task();

console.log(Validator.notNullValidatorMap)

let task3: Task = new Task();
task3.run(null);
//console.log(Validator.notNullValidatorMap)
//console.log("-- calling Task#run(null) --");
task.run(null);
//console.log("----------------");
//console.log("-- calling Task#run('test') --");
task.run("test");
//-------------------------------------------------------------------------------------------------------------------------------